import java.io.*;
import java.util.*;

public class Evaluator {

	public ArrayList<Symbol> symbolTable = new ArrayList<Symbol>(); // id, type,
																	// value
	public ArrayList<Node> current = new ArrayList<Node>();;
	Node astHead;
	Operator op = new Operator();

	public Evaluator(Node node) {
		astHead = node;
		if (astHead.getChildren() != null) { // head has children
			current = astHead.getChildren(); // current = children of head
			for (int i = 0; i < current.size(); i++) { // loop through children
														// of head

				if (current.get(i).getChildren() != null) { // if head node's
															// child has
															// children
					current = current.get(0).getChildren();
				}
				if (!current.isEmpty()) {
					while (current.get(0).getChildren() != null
							|| current.get(0).getChildren().get(0).isVisited() == true) {// go
																							// to
																							// leaf
																							// node
						System.out.println("loop");
						current = current.get(0).getChildren();
					}

					while (current.get(0).getParent() != astHead) {// then come
																	// back to
																	// the head
																	// node
						for (int j = 0; j < current.size(); j++) {
							if (current.get(j).getChildren() != null) { // if
																		// another
																		// child
																		// has
																		// more
																		// children
								current = current.get(j).getChildren();
								while (current.get(0).getChildren() != null
										|| current.get(0).getChildren().get(0)
												.isVisited() == true) {// go to
																		// leaf
																		// node
																		// of
																		// that
																		// child
									current = current.get(0).getChildren();
								}
							}
						}
						checkParent(current.get(0).getParent().getName(),
								current);
						current = current.get(0).getParent().getParent()
								.getChildren();
					}
					// sets the current to children of head before for loop
					// ends.
				}
			}
		} else {
			System.out.println("Error: AST is empty!");
		}
	}

	// Make sure to add the variable in the symbolTable
	// *****************************
	public void checkParent(String name, ArrayList<Node> children) {
		ArrayList<StringList> temp = new ArrayList<StringList>();
		if (name == "find") { // call find method with children
			System.out.println(current.get(0).getName());
			ArrayList<StringList> str = op.find(current.get(0).getName(),
					current.get(1).getName());
			if (current.get(0).getParent().getParent().getName().equals("=")
					|| current.get(0).getParent().getParent().getName()
							.equals("=#")) {
				temp = str;
				checkParent(current.get(0).getParent().getParent().getName(),
						current.get(0).getParent().getParent().getChildren());
				current.get(0).getParent().setVisited(true);
			}
			current.get(0).getParent().setVisited(true);
		} else if (name == "replace") {
			op.replace(current.get(0).getChildren().get(0).getName(), current
					.get(0).getChildren().get(1).getName(), current.get(1)
					.getChildren().get(0).getName(), current.get(0)
					.getChildren().get(1).getName());
			current.get(0).getParent().setVisited(true);
			// call the replace method
		} else if (name == "recursivereplace") {
			op.replace(current.get(0).getChildren().get(0).getName(), current
					.get(0).getChildren().get(1).getName(), current.get(1)
					.getChildren().get(0).getName(), current.get(0)
					.getChildren().get(1).getName());
			current.get(0).getParent().setVisited(true);
			// call the recursivereplace method
		} else if (name == "diff") {
			ArrayList<StringList> str1 = op.find(current.get(0).getChildren()
					.get(0).getName(), current.get(0).getChildren().get(1)
					.getName());
			ArrayList<StringList> str2 = op.find(current.get(1).getChildren()
					.get(0).getName(), current.get(1).getChildren().get(1)
					.getName());
			ArrayList<StringList> str = op.difference(str1, str2);
			if (current.get(0).getParent().getParent().getName().equals("=")
					|| current.get(0).getParent().getParent().getName()
							.equals("=#")) {
				temp = str;
				checkParent(current.get(0).getParent().getParent().getName(),
						current.get(0).getParent().getParent().getChildren());
				current.get(0).getParent().setVisited(true);
			}
			current.get(0).getParent().setVisited(true);
			// call the diff method
		} else if (name == "union") {
			ArrayList<StringList> str1 = op.find(current.get(0).getChildren()
					.get(0).getName(), current.get(0).getChildren().get(1)
					.getName());
			ArrayList<StringList> str2 = op.find(current.get(1).getChildren()
					.get(0).getName(), current.get(1).getChildren().get(1)
					.getName());
			ArrayList<StringList> str = op.union(str1, str2);
			if (current.get(0).getParent().getParent().getName().equals("=")
					|| current.get(0).getParent().getParent().getName()
							.equals("=#")) {
				temp = str;
				checkParent(current.get(0).getParent().getParent().getName(),
						current.get(0).getParent().getParent().getChildren());
				current.get(0).getParent().setVisited(true);
			}
			current.get(0).getParent().setVisited(true);
			// call the union method
		} else if (name == "inters") {
			ArrayList<StringList> str1 = op.find(current.get(0).getChildren()
					.get(0).getName(), current.get(0).getChildren().get(1)
					.getName());
			ArrayList<StringList> str2 = op.find(current.get(1).getChildren()
					.get(0).getName(), current.get(1).getChildren().get(1)
					.getName());
			ArrayList<StringList> str = op.inters(str1, str2);
			if (current.get(0).getParent().getParent().getName().equals("=")
					|| current.get(0).getParent().getParent().getName()
							.equals("=#")) {
				temp = str;
				checkParent(current.get(0).getParent().getParent().getName(),
						current.get(0).getParent().getParent().getChildren());
				current.get(0).getParent().setVisited(true);
			}
			current.get(0).getParent().setVisited(true);
			// call the inters method
		} else if (name == "print") {
			// call the print method
			for (int i = 0; i < symbolTable.size(); i++) {
				if (current.get(0).getName().equals(symbolTable.get(i).getId())) {

					if (symbolTable.get(i).getType().equals("int")) {
						op.print(Integer
								.parseInt(symbolTable.get(i).getValue()));
					} else {
						op.print(symbolTable.get(i).getStringList());
					}
				}
			}
			current.get(0).getParent().setVisited(true);
			/* if digit call digit print other wise call the other print */
		} else if (name == "=") {
			if (temp.size() > 0) {
				Symbol s = new Symbol(current.get(0).getName(), "stringList",
						temp);
				symbolTable.add(s);
			} else {
				String var = current.get(1).getName();
				for (int i = 0; i < symbolTable.size(); i++) {
					if (symbolTable.get(i).getId().equals(var)) {
						Symbol s = new Symbol(current.get(0).getName(),
								symbolTable.get(i).getType(), symbolTable
										.get(i).getValue());
						symbolTable.add(s);
					}
				}
			}
			current.get(0).getParent().setVisited(true);
		} else if (name == "=#") {
			if (temp.size() > 0) {
				Symbol s = new Symbol(current.get(0).getName(), "int",
						temp.size() + "");
				symbolTable.add(s);
			} else {
				String var = current.get(1).getName();
				for (int i = 0; i < symbolTable.size(); i++) {
					if (symbolTable.get(i).getId().equals(var)) {
						Symbol s = new Symbol(current.get(0).getName(), "int",
								symbolTable.get(i).getValue().length() + "");
						symbolTable.add(s);
					}
				}
			}
			current.get(0).getParent().setVisited(true);
		} else {
			System.out
					.println("Error: parent node has invalid value. Parent node recieved is: "
							+ name);
			System.exit(1);
		}
	}

	public void printSymbolTable() {
		for (Symbol s : symbolTable) {
			System.out.println("Symbol ID==" + s.getId() + ",TYPE=="
					+ s.getType() + ",VALUE==" + s.getValue());
		}
	}
}
